/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_real_constant.h                                                    *
 ****************************************************************************/

/**
 * @file elisa_real_constant.h
 * @brief Classes for real constants.
 */


#ifndef _elisa_real_const_h_
#define _elisa_real_const_h_ 1

#include "elisa_constant.h"
#include "elisa_interval.h"
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>

NAMESPACE_ELISA
//forward declaration
class RealConstant;

//--------------------------------------------------------------------------
// class RealConstantStock
//--------------------------------------------------------------------------


/**
 * @ingroup RealConstraint
 * @class RealConstantStock
 * @brief Base class to stock the value of a real constant
 */
class RealConstantStock
{
public:
	/**
 	 * @brief construtor
 	 */
	RealConstantStock();

	/**
 	 * @brief Destructor
 	 */
	virtual ~RealConstantStock()
	{
	};

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the value constant must be printed
 	 */
	virtual void print(std::ostream & os) const = 0;

	/**
 	 * @brief return the double closest to the real value
 	 * @return a double near the value of the constant
 	 */
	virtual double getValue() const = 0;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	virtual Interval getInterval() const = 0;

protected:

	// copy protection
	RealConstantStock & operator=(const RealConstantStock & right)
	{
	}
	RealConstantStock(const RealConstantStock & right)
	{
	}
};

inline RealConstantStock::RealConstantStock()
{
}

//--------------------------------------------------------------------------
// class DenseMatrix: implementation of members
//--------------------------------------------------------------------------

/**
 * @ingroup RealConstraint
 * @class ConstFloat
 * @brief Base class to stock the float, double or string value of a real constant
 */
class ConstFloat : public RealConstantStock
{
public:
	/**
 	 * @brief Constructor
 	 */
	ConstFloat()
	{
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	ConstFloat (float v)
	{
		_val = v;
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	ConstFloat (double v)
	{
		_val = v;
	}

	/// copy operator
	ConstFloat & operator=(const ConstFloat & right)
	{
		_val = right._val;
	}

	/// copy constructor
	ConstFloat(const ConstFloat & right) : RealConstantStock(right)
	{
		_val = right._val;
	}

	/**
 	 * @brief destructor
 	 */
	~ConstFloat();

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the value constant must be printed
 	 */
	void print(std::ostream & os) const;

	/**
 	 * @brief return the double closest to the real value
 	 * @return a double near the value of the constant
 	 */
	double getValue() const;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	Interval getInterval() const;

private:
	// @var the GMP value
	double _val;
};

/**
 * @ingroup RealConstraint
 * @class ConstRationnal
 * @brief Base class to stock the rationnal value of a real constant
 */
class ConstRationnal : public RealConstantStock
{
public:
	/**
 	 * @brief Constructor
 	 */
	ConstRationnal()
	{
	}

	/**
 	 * @brief Constructor base on a rationnal
 	 * @param num the value of the numerator
 	 * @param den the value of the denominator
 	 */
	ConstRationnal(int num,
	               int den)
	{
		_num = num;
		_den = den;
	}

	/// copy constructor
	ConstRationnal(const ConstRationnal & right) : RealConstantStock(right)
	{
		_num = right._num;
		_den = right._den;
	}

	/// copy operator
	ConstRationnal &
	operator=(const ConstRationnal & right)
	{
		_num = right._num;
		_den = right._den;
	}

	/**
 	 * @brief destructor
 	 */
	~ConstRationnal();

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the value constant must be printed
 	 */
	void print(std::ostream & os) const;

	/**
 	 * @brief return the double closest to the real value
 	 * @return a double near the value of the constant
 	 */
	double getValue() const;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	Interval getInterval() const;

private:
	int _num;
	int _den;
};



/**
 * @ingroup RealConstraint
 * @class ConstRationnal
 * @brief Base class to stock the rationnal value of a real constant
 */
class ConstString : public RealConstantStock
{
public:
	/**
 	 * @brief Constructor
 	 */
	ConstString()
	{
	}

	/**
 	 * @brief Constructor base on a rationnal
 	 * @param num the value of the numerator
 	 * @param den the value of the denominator
 	 */
	ConstString(std::string val)
	{
		_val = val;
	}

	/// copy constructor
	ConstString(const ConstString & right) : RealConstantStock(right)
	{
		_val = right._val;
	}

	/// copy operator
	ConstString &
	operator=(const ConstString & right)
	{
		_val = right._val;
	}

	/**
 	 * @brief destructor
 	 */
	~ConstString();

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the value constant must be printed
 	 */
	void print(std::ostream & os) const;

	/**
 	 * @brief return the double closest to the real value
 	 * @return a double near the value of the constant
 	 */
	double getValue() const;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	Interval getInterval() const;

private:
	// @var the GMP value
	std::string _val;
};

/**
 * @ingroup RealConstraint
 * @class ConstInt
 * @brief Base class to stock the integer value of a real constant
 */
class ConstInt : public RealConstantStock
{
public:
	/**
 	 * @brief Constructor
 	 */
	ConstInt()
	{
	}

	/**
 	 * @brief Constructor base on a rationnal
 	 * @param num the value of the numerator
 	 * @param den the value of the denominator
 	 */
	ConstInt(int val)
	{
		_val = val;
	}

	/// copy operator
	ConstInt(const ConstInt & right) : RealConstantStock(right)
	{
		_val = right._val;
	}


	/// copy constructor
	ConstInt &
	operator=(const ConstInt & right)
	{
		_val = right._val;
	}

	/**
 	 * @brief destructor
 	 */
	~ConstInt();

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the value constant must be printed
 	 */
	void print(std::ostream & os) const;

	/**
 	 * @brief return the double closest to the real value
 	 * @return a double near the value of the constant
 	 */
	double getValue() const;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	Interval getInterval() const;

private:
	int _val;
};

//--------------------------------------------------------------------------
// class RealConstant
//--------------------------------------------------------------------------

/**
 * @ingroup RealConstraint
 * @class RealConstant
 * @brief Symbolic representation of real constant
 */
class RealConstant : public Constant
{
public:
	/**
 	 * @brief Constructor
 	 */
	RealConstant()
	{
		_value = new ConstFloat(0.0);
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	RealConstant (int val) : Constant()
	{
		_value = new ConstInt(val);
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	RealConstant (long val) : Constant()
	{
		_value = new ConstInt(val);
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	RealConstant (float val) : Constant()
	{
		_value = new ConstFloat(val);
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	RealConstant (double val) : Constant()
	{
		_value = new ConstFloat(val);
	}

	/**
 	 * @brief Constructors
 	 * @param val the value of the constant
 	 */
	RealConstant (const std::string & val) : Constant()
	{
		_value = new ConstString(val);
	}

	/// copy constructor
	RealConstant(const RealConstant & right) : Constant(right)
	{
		ConstFloat *tempFloat = dynamic_cast<ConstFloat *>(right._value);
		ConstInt *tempInt = dynamic_cast<ConstInt *>(right._value);
		ConstRationnal *tempR = dynamic_cast<ConstRationnal *>(right._value);
		ConstString *tempStr = dynamic_cast<ConstString *>(right._value);

		if (tempFloat != 0) {
			_value = new ConstFloat(*tempFloat);
		} else if (tempInt != 0) {
			_value = new ConstInt(*tempInt);
		} else if (tempR != 0) {
			_value = new ConstRationnal(*tempR);
		} else if (tempStr != 0) {
			_value = new ConstString(*tempStr);
		}
	}

	/// copy operator
	RealConstant &
	operator=(const RealConstant & right)
	{
		ConstFloat *tempFloat = dynamic_cast<ConstFloat *>(right._value);
		ConstInt *tempInt = dynamic_cast<ConstInt *>(right._value);
		ConstRationnal *tempR = dynamic_cast<ConstRationnal *>(right._value);
		ConstString *tempStr = dynamic_cast<ConstString *>(right._value);

		if (tempFloat != 0) {
			_value = new ConstFloat(*tempFloat);
		} else if (tempInt != 0) {
			_value = new ConstInt(*tempInt);
		} else if (tempR != 0) {
			_value = new ConstRationnal(*tempR);
		} else if (tempStr != 0) {
			_value = new ConstString(*tempStr);
		}
		// ishii
		return *this;
	}

	/**
 	 * @brief Constructor base on a rationnal
 	 * @param num the value of the numerator
 	 * @param den the value of the denominator
 	 */
	RealConstant (int num, int den) : Constant()
	{
		_value = new ConstRationnal(num, den);
	}

	/// affectation operation
	//@{
	RealConstant &
	operator=(const double val)
	{
		delete _value;
		_value = new ConstFloat(val);
		return *this;
	}

	RealConstant &
	operator=(const float val)
	{
		delete _value;
		_value = new ConstFloat(val);
		return *this;
	}

	RealConstant &
	operator=(const int val)
	{
		delete _value;
		_value = new ConstInt(val);
		return *this;
	}

	RealConstant &
	operator=(const std::string & val)
	{
		delete _value;
		_value = new ConstString(val);
		return *this;
	}
	//@}

	/**
 	 * Destructor
 	 */
	virtual ~RealConstant();

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the value constant must be printed
 	 */
	void print(std::ostream & os) const;

	/**
 	 * @brief return the double closest to the real value
 	 * @return a double near the value of the constant
 	 */
	double getValue() const;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	Interval getInterval() const;

private:

	// @var the value of the constant.
	RealConstantStock *_value;
};


/**
 * @ingroup RealConstraint
 * @class IntConstant
 * @brief Symbolic representation of integer constant
 */
class IntConstant : public RealConstant {
public:

	/// default constructor
	IntConstant() : RealConstant(0)
	{
	}

	/// constructor with an int
	IntConstant(int val) : RealConstant(val)
	{
	}

	/// constructor with a long
	IntConstant(long val) : RealConstant(val)
	{
	}
};


//--------------------------------------------------------------------------
// class IntervalConstant
//--------------------------------------------------------------------------

/**
 * @ingroup RealConstraint
 * @class IntervalConstant
 * @brief Symbolic representation of real constant by an interval
 */
class IntervalConstant : public Constant
{
public:
	/**
 	 * @brief Constructor
 	 */
	IntervalConstant()
	{
		_inf = new ConstFloat(0.0);
		_sup = new ConstFloat(0.0);
	}

	/**
 	 * @brief Constructors
 	 * @param inf and sup the bounds of the constant interval
 	 */
	IntervalConstant (const int inf, const int sup) : Constant()
	{
		_inf = new ConstInt(inf);
		_sup = new ConstInt(sup);
	}

	/**
 	 * @brief Constructors
 	 * @param inf and sup the bounds of the constant interval
 	 */
	IntervalConstant (const long inf, const long sup) : Constant()
	{
		_inf = new ConstInt(inf);
		_sup = new ConstInt(sup);
	}

	/**
 	 * @brief Constructors
 	 * @param inf and sup the bounds of the constant
 	 */
	IntervalConstant (const float inf, const float sup) : Constant()
	{
		_inf = new ConstFloat(inf);
		_sup = new ConstFloat(inf);
	}

	/**
 	 * @brief Constructors
 	 * @param inf and sup the bounds of the constant
 	 */
	IntervalConstant (const double inf, const double sup) : Constant()
	{
		_inf = new ConstFloat(inf);
		_sup = new ConstFloat(sup);
	}

	/**
 	 * @brief Constructors
 	 * @param inf and sup the bounds of the constant
 	 */
	IntervalConstant (const std::string & inf, const std::string & sup) : Constant()
	{
		_inf = new ConstString(inf);
		_sup = new ConstString(sup);
	}

	/**
 	 * @brief Constructors
 	 * @param i the value of the constant
 	 */
	IntervalConstant(const Interval& i)
	{
		_inf = new ConstFloat(i.inf());
		_sup = new ConstFloat(i.sup());
	}

	/**
 	 * Destructor
 	 */
	~IntervalConstant();

	/**
 	 * @brief Print the constant in a stream
 	 * @param o the stream where the constant must be printed
 	 */
	void print(std::ostream & os) const;

	/**
 	 * @brief return the double closest to the real bound inf
 	 * @return a double near the value of the bound inf
 	 */
	double getInf() const;

	/**
 	 * @brief return the double closest to the real bound sup
 	 * @return a double near the value of the bound sup
 	 */
	double getSup() const;

	/**
 	 * @brief return the interval surroundin the real value
 	 * @return an interval surrounding the value of the constant
 	 */
	Interval getInterval() const;

	/// copy operator
	IntervalConstant &
	operator=(const IntervalConstant & right)
	{
		ConstFloat *tempFloat = dynamic_cast<ConstFloat *>(right._inf);
		ConstInt *tempInt = dynamic_cast<ConstInt *>(right._inf);
		ConstRationnal *tempR = dynamic_cast<ConstRationnal *>(right._inf);
		ConstString *tempStr = dynamic_cast<ConstString *>(right._inf);

		if (tempFloat != 0) {
			_inf = new ConstFloat(*tempFloat);
		} else if (tempInt != 0) {
			_inf = new ConstInt(*tempInt);
		} else if (tempR != 0) {
			_inf = new ConstRationnal(*tempR);
		} else if (tempStr != 0) {
			_inf = new ConstString(*tempStr);
		}

		tempFloat = dynamic_cast<ConstFloat *>(right._sup);
		tempInt = dynamic_cast<ConstInt *>(right._sup);
		tempR = dynamic_cast<ConstRationnal *>(right._sup);
		tempStr = dynamic_cast<ConstString *>(right._sup);

		if (tempFloat != 0) {
			_sup = new ConstFloat(*tempFloat);
		} else if (tempInt != 0) {
			_sup = new ConstInt(*tempInt);
		} else if (tempR != 0) {
			_sup = new ConstRationnal(*tempR);
		} else if (tempStr != 0) {
			_sup = new ConstString(*tempStr);
		}
		// ishii
		return *this;
	}


	/// copy constructor
	IntervalConstant(const IntervalConstant & right) : Constant(right)
	{
		ConstFloat *tempFloat = dynamic_cast<ConstFloat *>(right._inf);
		ConstInt *tempInt = dynamic_cast<ConstInt *>(right._inf);
		ConstRationnal *tempR = dynamic_cast<ConstRationnal *>(right._inf);
		ConstString *tempStr = dynamic_cast<ConstString *>(right._inf);

		if (tempFloat != 0) {
			_inf = new ConstFloat(*tempFloat);
		} else if (tempInt != 0) {
			_inf = new ConstInt(*tempInt);
		} else if (tempR != 0) {
			_inf = new ConstRationnal(*tempR);
		} else if (tempStr != 0) {
			_inf = new ConstString(*tempStr);
		}

		tempFloat = dynamic_cast<ConstFloat *>(right._sup);
		tempInt = dynamic_cast<ConstInt *>(right._sup);
		tempR = dynamic_cast<ConstRationnal *>(right._sup);
		tempStr = dynamic_cast<ConstString *>(right._sup);

		if (tempFloat != 0) {
			_sup = new ConstFloat(*tempFloat);
		} else if (tempInt != 0) {
			_sup = new ConstInt(*tempInt);
		} else if (tempR != 0) {
			_sup = new ConstRationnal(*tempR);
		} else if (tempStr != 0) {
			_sup = new ConstString(*tempStr);
		}
	}

private:
	// @var the bound inf of the constant interval.
	RealConstantStock *_inf;

	// @var the bound sup of the constant interval.
	RealConstantStock *_sup;
};

END_NAMESPACE_ELISA
#endif // ELISA_REAL_CONSTANT_H
